package core

import (
	"strings"
)

// ContextNode  代码区间树
type ContextNode struct {
	prev *ContextNode // 指向上一个 *RunningChunk
	next ContextNodes // 指向下一个 *RunningChunk，可以包含多个节点

	From  int                    // 开始行数
	End   int                    // 结束行数
	Depth int                    // 树的深度
	Code  Code                   // 源代码语句
	Node  *Node                  // 语法树节点
	Vars  map[string]interface{} // 变量绑定表
	Skip  bool                   //是否跳过
}

// NewContextTree 创建代码区间树节点
func NewContextTree() *ContextNode {
	return &ContextNode{
		From: -1,
		End:  -1,
		next: []*ContextNode{},
	}
}

// Width 获取区间宽度
func (c *ContextNode) Width() int {

	return c.End - c.From
}

// Contain 判断区间是否包含某行
func (c *ContextNode) Contain(row int) bool {

	return c.From <= row && row <= c.End
}

// ContextNodes 代码区间树所有节点集合
type ContextNodes []*ContextNode

// FindDepth 根据行数获取树深度
func (c ContextNodes) FindDepth(row int) int {
	res := 0
	width := c[0].Width() // 区间宽度

	for _, tree := range c {
		if !tree.Contain(row) {
			continue
		}

		if tree.Width() < width {
			res = tree.Depth
		}
	}

	return res
}

// FindNode 根据行数获取树节点
func (c ContextNodes) FindNode(row int) *ContextNode {
	res := c[0]
	width := c[0].Width() // 区间宽度

	for _, tree := range c {
		if !tree.Contain(row) {
			continue
		}

		if tree.Width() < width {
			res = tree
		}
	}

	return res
}

// MaxDepth 获取树最大深度
func (c ContextNodes) MaxDepth() int {
	res := 0

	for _, tree := range c {
		if res < tree.Depth {
			res = tree.Depth
		}
	}

	return res
}

// seekNodes 遍历树的所有节点
func seekNodes(ptr *ContextNode) ContextNodes {
	var trees ContextNodes

	trees = append(trees, ptr)

	if ptr.next == nil {
		return trees
	}

	for _, child := range ptr.next {
		trees = append(trees, child)
		if child.next == nil {
			continue
		}

		for _, grandChild := range child.next {
			trees = append(trees, seekNodes(grandChild)...)
		}
	}

	return trees
}

// GenerateTrees 生成代码区间树
func GenerateTrees(rows StandardCode) ContextNodes {

	ptr := NewContextTree()

	for i, row := range rows {

		// 处理首行
		if AnnoTagsDefault.Include(row) {
			ptr.From = 0
			ptr.Code = Code(row)
			ptr.Node = Parse(ptr.Code)
			ptr.Node.Line = ptr.From
			ptr.Node.ContextNode = ptr
			ptr.Vars = make(map[string]interface{})
			continue
		}
		if strings.HasPrefix(row, "@") {

			if ptr.From < 0 {
				ptr.From = i
				continue
			}

			// 创建子节点
			next := NewContextTree()
			ptr.next = append(ptr.next, next)

			// 初始化子节点
			next.From = i
			next.prev = ptr
			next.Depth = ptr.Depth + 1
			next.Code = Code(row)
			next.Node = Parse(next.Code)
			next.Node.Line = next.From
			next.Node.ContextNode = next
			next.Vars = make(map[string]interface{})
			// 链接节点
			ptr = next

			continue
		}

		if row == "}" {
			ptr.End = i
			if ptr.prev != nil {
				ptr = ptr.prev
			}
		}
	}

	return seekNodes(ptr)
}
